using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System;
using System.Linq;

// ReSharper disable CheckNamespace
namespace Pharmacy.Ultilities
{
    /// <summary>
    /// Represents an alternative for Linq in .Net Framework 2.0.
    /// It also exposes the enumerator, which supports a simple iteration over a collection of a specified type.
    /// </summary>
    /// <author>ThangTran</author>
    /// <history>
    /// 2011.01.29 - ThangTran: improved performance for Linq queries.
    /// 2011.04.06 - ThangTran: added Count(), LongCount(), Take(), While(), Aggregate().
    /// 2011.04.14 - ThangTran: renamed static void ToLinq() to From() to follow LINQ naming convention.
    /// 2011.05.06 - ThangTran: added GroupBy(), ToLookUp().
    /// 2011.06.23 - ThangTran: added All(), modified Except(), Intersect().
    /// 2011.07.14 - ThangTran: added Each(), Yield(), Last(), LastOrDefault().
    /// 2011.07.20 - ThangTran: attached attribute [DebuggerStepThrough, DebuggerNonUserCode] to all methods.
    /// 2011.07.28 - ThangTran: attached attribute [DebuggerStepThrough, DebuggerNonUserCode] to all methods.
    /// </history>
    public static class LinqToObject
    {
        /// <summary>
        /// Allows LINQ usage of given <see cref="IEnumerable{T}"/> collection.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns>LINQ-able object.</returns>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public static LinqToObject<T> From<T>(IEnumerable<T> source)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(source != null);
            // --- End parameters checking code -------------------------------

            return new LinqToObject<T>(source);
        }

        /// <summary>
        /// Allows LINQ usage of given <see cref="IEnumerable"/> collection.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns>LINQ-able object.</returns>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public static LinqToObject<T> From<T>(IEnumerable source)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(source != null);
            // --- End parameters checking code -------------------------------

            return new LinqToObject<T>(LinqToObject<T>.Yield<T, T>(source, delegate(T item) { return item; }, null));
        }        

        // ====================================================================
        // Below methods do not exist in original LINQ set 
        // ====================================================================

        /// <summary>
        /// Performs the specified action on each element of the LinqToObject(<see cref="T"/>).
        /// </summary>
        public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
        {
            foreach (T item in source)
            {
                action(item);
            }
        }

        /// <summary>
        /// Performs the specified action on each element of the LinqToObject(<see cref="T"/>).
        /// The index of element in the foreach loop with be passed to the method.
        /// </summary>
        public static void ForEach<T>(this IEnumerable<T> source, Action<T, int> action)
        {
            int i = 0;
            foreach (T item in source)
            {
                action(item, i++);
            }
        }


        /// <summary>
        /// Attaches the specified action on each element of the LinqToObject(<see cref="T"/>) and continues the query chain.
        /// </summary>
        public static IEnumerable<T> Each<T>(this IEnumerable<T> source, Action<T> action)
        {
            return Each(source, (t, index) => action(t));
        }

        /// <summary>
        /// Attaches the specified action on each element of the LinqToObject(<see cref="T"/>) and continues the query chain.
        /// The index of element in the foreach loop with be passed to the method.
        /// </summary>
        public static IEnumerable<T> Each<T>(this IEnumerable<T> source, Action<T, int> action)
        {
            int i = 0;
            foreach (T item in source)
            {
                if (action != null)
                {
                    action(item, i++);
                }
                yield return item;
            }
        }

        /// <summary>
        /// Executes the whole query and continues a new query chain.
        /// </summary>
        public static IEnumerable<T> Execute<T>(this IEnumerable<T> source)
        {
            return source.ToArray();
        }

    }

    /// <summary>
    /// Represents an alternative for Linq in .Net Framework 2.0.
    /// It also exposes the enumerator, which supports a simple iteration over a collection of a specified type.
    /// </summary>
    /// <typeparam name="T">Type associated with this Linq.</typeparam>
    public class LinqToObject<T> : IEnumerable<T>
    {
        /// <summary>
        /// Gets or sets internal data source.
        /// </summary>
        private readonly IEnumerable<T> _source;

        /// <summary>
        /// Initializes a new instance of the <see cref="LinqToObject"/> class.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject(IEnumerable<T> source)
        {
            _source = source;
        }

        /// <summary>
        /// Returns an enumerator that iterates through the collection.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
        /// </returns>
        /// <filterpriority>1</filterpriority>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public virtual IEnumerator<T> GetEnumerator()
        {
            return _source.GetEnumerator();
        }

        /// <summary>
        /// Returns an enumerator that iterates through a collection.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
        /// </returns>
        /// <filterpriority>2</filterpriority>
        [DebuggerStepThrough, DebuggerNonUserCode]
        IEnumerator IEnumerable.GetEnumerator()
        {
            return _source.GetEnumerator();
        }

        /// <summary>
        /// Yields results by using yield return.
        /// This is used by internal functions.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        internal static IEnumerable<TResult> Yield<TSource, TResult>(
            IEnumerable source,
            Func<TSource, TResult> selector,
            Func<TSource, bool> predicate)
        {
            foreach (TSource item in source)
            {
                if (predicate != null)
                {
                    if (!predicate(item))
                    {
                        continue;
                    }
                }

                yield return selector(item);
            }
        }

        /// <summary>
        /// Yields results by using yield return.
        /// This is used by internal functions.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        internal static IEnumerable<TResult> Yield<TSource, TResult>(
            IEnumerable source,
            Func<TSource, int, TResult> selector,
            Func<TSource, int, bool> predicate)
        {
            return Yield(source, selector, predicate, null);
        }

        /// <summary>
        /// Yields results by using yield return.
        /// This is used by internal functions.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        internal static IEnumerable<TResult> Yield<TSource, TResult>(
            IEnumerable source,
            Func<TSource, int, TResult> selector,
            Func<TSource, int, bool> predicate,
            Action<TSource, int> action)
        {
            int i = -1;
            foreach (TSource item in source)
            {
                i++;
                if (predicate != null)
                {
                    if (!predicate(item, i))
                    {
                        continue;
                    }
                }

                if (action != null)
                {
                    action(item, i);
                }

                yield return selector(item, i);
            }
        }

        /// <summary>
        /// Projects each element of a sequence into a new form.
        /// </summary>        
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<TResult> Select<TResult>(Func<T, TResult> selector)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(selector != null);
            // --- End parameters checking code -------------------------------

            return new LinqToObject<TResult>(Yield(this, selector, null));
        }

        /// <summary>
        /// Projects each element of a sequence into a new form by incorporating the element's index.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<TResult> Select<TSource, TResult>(Func<TSource, int, TResult> selector)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(selector != null);
            // --- End parameters checking code -------------------------------

            return new LinqToObject<TResult>(Yield(this, selector, null));
        }


        /// <summary>
        /// Performs the specified action on each element of the LinqToObject(<see cref="T"/>).
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public void ForEach(Action<T> action)
        {
            foreach (T item in this)
            {
                action(item);
            }
        }

        /// <summary>
        /// Performs the specified action on each element of the LinqToObject(<see cref="T"/>).
        /// The index of element in the foreach loop with be passed to the method.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public void ForEach(Action<T, int> action)
        {
            int i = 0;
            foreach (T item in this)
            {
                action(item, i++);
            }
        }

        /// <summary>
        /// Filters a sequence of values based on a predicate. 
        /// Each element's index is used in the logic of the predicate function.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<T> Where(Func<T, bool> predicate)
        {
            // if predicate equals to null, it means there is alwasy true
            if (predicate == null) return this;

            return new LinqToObject<T>(Yield<T, T>(this, delegate(T item) { return item; }, predicate));
        }

        /// <summary>
        /// Filters a sequence of values based on a predicate. 
        /// Each element's index is used in the logic of the predicate function.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<T> Where(Func<T, int, bool> predicate)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(predicate != null);
            // --- End parameters checking code -------------------------------

            return new LinqToObject<T>(Yield<T, T>(this, delegate(T item, int index) { return item; }, predicate));
        }


        /// <summary>
        /// Determines whether a sequence contains any element.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public bool Any()
        {
            using (IEnumerator<T> e = this.GetEnumerator())
            {
                return e.MoveNext();
            }
        }

        /// <summary>
        /// Determines whether any element of a sequence satisfies a condition.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public bool Any(Func<T, bool> predicate)
        {
            return this.Where(predicate).Any();
        }

        /// <summary>
        /// Determines whether all elements of a sequence satisfy a condition.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public bool All(Func<T, bool> predicate)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(predicate != null);
            // --- End parameters checking code -------------------------------

            foreach (T item in this)
            {
                if (!predicate(item))
                {
                    return false;
                }
            }

            return true;
        }


        /// <summary>
        /// Internal used class.
        /// </summary>
        private static class Futures
        {
            public static readonly Func<T> Default = delegate { return default(T); };
            public static readonly Func<T> Undefined = delegate { throw new InvalidOperationException(); };
        }

        /// <summary>
        /// Base implementation of Single operator.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        private T SingleImpl(Func<T> empty)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(empty != null);
            // --- End parameters checking code -------------------------------

            using (IEnumerator<T> e = this.GetEnumerator())
            {
                if (e.MoveNext())
                {
                    T single = e.Current;
                    if (!e.MoveNext())
                    {
                        return single;
                    }

                    throw new InvalidOperationException();
                }

                return empty();
            }
        }

        /// <summary>
        /// Returns the only element of a sequence, and throws an exception 
        /// if there is not exactly one element in the sequence.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public T Single()
        {
            return this.SingleImpl(Futures.Undefined);
        }

        /// <summary>
        /// Returns the only element of a sequence that satisfies a 
        /// specified condition, and throws an exception if more than one 
        /// such element exists.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public T Single(Func<T, bool> predicate)
        {
            return this.Where(predicate).Single();
        }

        /// <summary>
        /// Returns the only element of a sequence, or a default value if 
        /// the sequence is empty; this method throws an exception if there 
        /// is more than one element in the sequence.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public T SingleOrDefault()
        {
            return this.SingleImpl(Futures.Default);
        }

        /// <summary>
        /// Returns the only element of a sequence that satisfies a 
        /// specified condition or a default value if no such element 
        /// exists; this method throws an exception if more than one element 
        /// satisfies the condition.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public T SingleOrDefault(Func<T, bool> predicate)
        {
            return this.Where(predicate).SingleOrDefault();
        }

        /// <summary>
        /// Creates a <see cref="List{T}"/> from an <see cref="IEnumerable{T}"/>.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public List<T> ToList()
        {
            return new List<T>(this);
        }

        /// <summary>
        /// Creates an array from an <see cref="IEnumerable{T}"/>.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public T[] ToArray()
        {
            return this.ToList().ToArray();
        }

        /// <summary>
        /// Base implementation for Intersect and Except operators.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        private LinqToObject<T> IntersectExceptImpl(IEnumerable<T> second, IEqualityComparer<T> comparer, bool flag)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(second != null);
            // --- End parameters checking code -------------------------------

            List<T> keys = new List<T>();
            Dictionary<T, bool> flags = new Dictionary<T, bool>(comparer);

            foreach (T item in this.Where(delegate(T k) { return !flags.ContainsKey(k); }))
            {
                flags.Add(item, !flag);
                keys.Add(item);
            }

            foreach (T item in LinqToObject.From(second).Where(flags.ContainsKey))
            {
                flags[item] = flag;
            }

            //
            // As per docs, "the marked elements are yielded in the order in 
            // which they were collected.
            //
            return LinqToObject
                .From(keys)
                .Where(delegate(T item) { return flags[item]; });
        }

        /// <summary>
        /// Produces the set intersection of two sequences by using the 
        /// default equality comparer to compare values.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<T> Intersect(params T[] secondItems)
        {
            return LinqToObject.From(secondItems).Intersect(secondItems, /* comparer */ null);
        }

        /// <summary>
        /// Produces the set intersection of two sequences by using the 
        /// default equality comparer to compare values.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<T> Intersect(IEnumerable<T> second)
        {
            return LinqToObject.From(second).Intersect(second, /* comparer */ null);
        }

        /// <summary>
        /// Produces the set intersection of two sequences by using the 
        /// specified <see cref="IEqualityComparer{T}" /> to compare values.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<T> Intersect(IEnumerable<T> second, IEqualityComparer<T> comparer)
        {
            return this.IntersectExceptImpl(second, comparer, /* flag */ true);
        }

        /// <summary>
        /// Produces the set difference of two sequences by using the 
        /// default equality comparer to compare values.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<T> Except(params T[] secondItems)
        {
            return this.Except(secondItems, /* comparer */ null);
        }

        /// <summary>
        /// Produces the set difference of two sequences by using the 
        /// default equality comparer to compare values.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<T> Except(IEnumerable<T> second)
        {
            return this.Except(second, /* comparer */ null);
        }

        /// <summary>
        /// Produces the set difference of two sequences by using the 
        /// specified <see cref="IEqualityComparer{T}" /> to compare values.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<T> Except(IEnumerable<T> second, IEqualityComparer<T> comparer)
        {
            return this.IntersectExceptImpl(second, comparer, /* flag */ false);
        }

        /// <summary>
        /// Converts the elements of an <see cref="IEnumerable"/> to the 
        /// specified type.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<TResult> Cast<TResult>()
        {
            return new LinqToObject<TResult>(Yield<T, TResult>(this, delegate(T item) { return (TResult)(object)item; }, null));
        }

        /// <summary>
        /// Filters the elements of an <see cref="IEnumerable"/> based on a specified type.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<TResult> OfType<TResult>()
        {
            List<TResult> result = new List<TResult>();

            foreach (object item in this)
            {
                if (item is TResult)
                {
                    result.Add((TResult)item);
                }
            }

            return new LinqToObject<TResult>(result);
        }

        /// <summary>
        /// Base implementation of First operator.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        private T FirstImpl(Func<T> empty)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(empty != null);
            // --- End parameters checking code -------------------------------

            IList<T> list = this as IList<T>; // optimized case for lists
            if (list != null)
            {
                return list.Count > 0 ? list[0] : empty();
            }

            using (IEnumerator<T> e = this.GetEnumerator()) // fallback for enumeration
            {
                return e.MoveNext() ? e.Current : empty();
            }
        }

        /// <summary>
        /// Returns the first element of a sequence.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public T First()
        {
            return this.FirstImpl(Futures.Undefined);
        }

        /// <summary>
        /// Returns the first element in a sequence that satisfies a specified condition.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public T First(Func<T, bool> predicate)
        {
            return LinqToObject.From(this).Where(predicate).Single();
        }

        /// <summary>
        /// Returns the first element of a sequence, or a default value if 
        /// the sequence contains no elements.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public T FirstOrDefault()
        {
            return this.FirstImpl(Futures.Default);
        }

        /// <summary>
        /// Returns the first element of the sequence that satisfies a 
        /// condition or a default value if no such element is found.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public T FirstOrDefault(Func<T, bool> predicate)
        {
            return LinqToObject.From(this).Where(predicate).FirstOrDefault();
        }

        /// <summary>
        /// Base implementation of Last operator.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        private T LastImpl(Func<T> empty)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(empty != null);
            // --- End parameters checking code -------------------------------

            IList<T> list = this as IList<T>;    // optimized case for lists
            if (list != null)
            {
                return list.Count > 0 ? list[list.Count - 1] : empty();
            }

            using (IEnumerator<T> e = this.GetEnumerator())
            {
                if (!e.MoveNext())
                {
                    return empty();
                }

                T last = e.Current;
                while (e.MoveNext())
                {
                    last = e.Current;
                }

                return last;
            }
        }

        /// <summary>
        /// Returns the last element of a sequence.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public T Last()
        {
            return this.LastImpl(Futures.Undefined);
        }

        /// <summary>
        /// Returns the last element of a sequence that satisfies a specified condition.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public T Last(Func<T, bool> predicate)
        {
            return this.Where(predicate).Last();
        }

        /// <summary>
        /// Returns the last element of a sequence, or a default value if the sequence contains no elements.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public T LastOrDefault()
        {
            return this.LastImpl(Futures.Default);
        }

        /// <summary>
        /// Returns the last element of a sequence that satisfies a 
        /// condition or a default value if no such element is found.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public T LastOrDefault(Func<T, bool> predicate)
        {
            return this.Where(predicate).LastOrDefault();
        }

        /// <summary>
        /// Projects each element of a sequence to an <see cref="IEnumerable{T}" /> 
        /// and flattens the resulting sequences into one sequence.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<TResult> SelectMany<TResult>(Func<T, IEnumerable> selector)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(selector != null);
            // --- End parameters checking code -------------------------------

            return this.SelectMany<TResult>(delegate(T item, int i) { return selector(item); });
        }

        /// <summary>
        /// Projects each element of a sequence to an <see cref="IEnumerable{T}" />, 
        /// and flattens the resulting sequences into one sequence. The 
        /// index of each source element is used in the projected form of 
        /// that element.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<TResult> SelectMany<TResult>(Func<T, int, IEnumerable> selector)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(selector != null);
            // --- End parameters checking code -------------------------------

            return this.SelectMany<TResult, TResult>(selector, delegate(T item, TResult subitem) { return subitem; });
        }

        /// <summary>
        /// Projects each element of a sequence to an <see cref="IEnumerable{T}" />, 
        /// flattens the resulting sequences into one sequence, and invokes 
        /// a result selector function on each element therein.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<TResult> SelectMany<TCollection, TResult>(Func<T, IEnumerable> collectionSelector, Func<T, TCollection, TResult> resultSelector)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(resultSelector != null);
            // --- End parameters checking code -------------------------------

            return this.SelectMany(delegate(T item, int i) { return collectionSelector(item); }, resultSelector);
        }

        /// <summary>
        /// Projects each element of a sequence to an <see cref="IEnumerable{T}" />, 
        /// flattens the resulting sequences into one sequence, and invokes 
        /// a result selector function on each element therein. The index of 
        /// each source element is used in the intermediate projected form 
        /// of that element.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<TResult> SelectMany<TCollection, TResult>(Func<T, int, IEnumerable> collectionSelector, Func<T, TCollection, TResult> resultSelector)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(collectionSelector != null);
            Debug.Assert(resultSelector != null);
            // --- End parameters checking code -------------------------------

            return new LinqToObject<TResult>(this.SelectManyYield(collectionSelector, resultSelector));
        }

        /// <summary>
        /// Internal use SelectMany method.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        private IEnumerable<TResult> SelectManyYield<TCollection, TResult>(Func<T, int, IEnumerable> collectionSelector, Func<T, TCollection, TResult> resultSelector)
        {
            int i = 0;
            foreach (T item in this)
            {
                foreach (TCollection subitem in collectionSelector(item, i++))
                {
                    yield return resultSelector(item, subitem);
                }
            }
        }        

        /// <summary>
        /// Makes an enumerator seen as enumerable once more.
        /// </summary>
        /// <remarks>
        /// The supplied enumerator must have been started. The first element returned is the element the enumerator was on when passed in.
        /// DO NOT use this method if the caller must be a generator. It is mostly safe among aggregate operations.
        /// </remarks>
        [DebuggerStepThrough, DebuggerNonUserCode]
        private static IEnumerable<T> Renumerable(IEnumerator<T> e)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(e != null);
            // --- End parameters checking code -------------------------------

            do { yield return e.Current; } while (e.MoveNext());
        }

        /// <summary>
        /// Returns a specified number of contiguous elements from the start of a sequence.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<T> Take(int count)
        {
            return this.Where(delegate(T item, int i) { return i < count; });
        }

        /// <summary>
        /// Bypasses a specified number of elements in a sequence and then returns the remaining elements.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<T> Skip(int count)
        {
            return this.Where(delegate(T item, int i) { return i >= count; });
        }

        /// <summary>
        /// Applies an accumulator function over a sequence.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public T Aggregate(Func<T, T, T> func)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(func != null);
            // --- End parameters checking code -------------------------------

            using (IEnumerator<T> e = this.GetEnumerator())
            {
                if (!e.MoveNext())
                {
                    throw new InvalidOperationException();
                }

                return LinqToObject.From(Renumerable(e)).Skip(1).Aggregate(e.Current, func);
            }
        }

        /// <summary>
        /// Applies an accumulator function over a sequence. The specified 
        /// seed value is used as the initial accumulator value.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public TAccumulate Aggregate<TAccumulate>(TAccumulate seed, Func<TAccumulate, T, TAccumulate> func)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(func != null);
            // --- End parameters checking code -------------------------------

            return Aggregate<TAccumulate, TAccumulate>(seed, func, delegate(TAccumulate r) { return r; });
        }

        /// <summary>
        /// Applies an accumulator function over a sequence. The specified 
        /// seed value is used as the initial accumulator value, and the 
        /// specified function is used to select the result value.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public TResult Aggregate<TAccumulate, TResult>(TAccumulate seed, Func<TAccumulate, T, TAccumulate> func, Func<TAccumulate, TResult> resultSelector)
        {
            // --- Begin parameters checking code -----------------------------
            Debug.Assert(func != null);
            Debug.Assert(resultSelector != null);
            // --- End parameters checking code -------------------------------

            TAccumulate result = seed;

            foreach (T item in this)
            {
                result = func(result, item);
            }

            return resultSelector(result);
        }

        /// <summary>
        /// Returns the number of elements in a sequence.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public virtual int Count()
        {
            ICollection collection = this as ICollection;
            return collection != null
                 ? collection.Count
                 : this.Aggregate(0, delegate(int count, T item) { return checked(count + 1); });
        }

        /// <summary>
        /// Returns a number that represents how many elements in the 
        /// specified sequence satisfy a condition.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public int Count(Func<T, bool> predicate)
        {
            return this.Where(predicate).Count();
        }

        /// <summary>
        /// Returns an <see cref="Int64"/> that represents the total number of elements in a sequence.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public long LongCount()
        {
            Array array = this as Array;
            return array != null
                 ? array.LongLength
                 : this.Aggregate(0L, delegate(long count, T item) { return count + 1; });
        }

        /// <summary>
        /// Returns an <see cref="Int64"/> that represents how many elements in a sequence satisfy a condition.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public long LongCount(Func<T, bool> predicate)
        {
            return this.Where(predicate).LongCount();
        }

        /// <summary>
        /// Creates a <see cref="Dictionary{TKey,TValue}" /> from an 
        /// <see cref="IEnumerable{T}" /> according to a specified key 
        /// selector function.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public Dictionary<TKey, T> ToDictionary<TKey>(Func<T, TKey> keySelector)
        {
            return this.ToDictionary(keySelector, /* comparer */ null);
        }

        /// <summary>
        /// Creates a <see cref="Dictionary{TKey,TValue}" /> from an 
        /// <see cref="IEnumerable{T}" /> according to a specified key 
        /// selector function and key comparer.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public Dictionary<TKey, T> ToDictionary<TKey>(Func<T, TKey> keySelector, IEqualityComparer<TKey> comparer)
        {
            return this.ToDictionary<TKey, T>(keySelector, delegate(T e) { return e; });
        }

        /// <summary>
        /// Creates a <see cref="Dictionary{TKey,TValue}" /> from an 
        /// <see cref="IEnumerable{T}" /> according to specified key 
        /// selector and element selector functions.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public Dictionary<TKey, TElement> ToDictionary<TKey, TElement>(Func<T, TKey> keySelector, Func<T, TElement> elementSelector)
        {
            return this.ToDictionary(keySelector, elementSelector, /* comparer */ null);
        }

        /// <summary>
        /// Creates a <see cref="Dictionary{TKey,TValue}" /> from an 
        /// <see cref="IEnumerable{T}" /> according to a specified key 
        /// selector function, a comparer, and an element selector function.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public Dictionary<TKey, TElement> ToDictionary<TKey, TElement>(Func<T, TKey> keySelector, Func<T, TElement> elementSelector, IEqualityComparer<TKey> comparer)
        {
            Dictionary<TKey, TElement> dict = new Dictionary<TKey, TElement>(comparer);

            foreach (T item in this)
            {
                //
                // ToDictionary is meant to throw ArgumentNullException if
                // keySelector produces a key that is null and 
                // Argument exception if keySelector produces duplicate keys 
                // for two elements. Incidentally, the doucmentation for
                // IDictionary<TKey, TValue>.Add says that the Add method
                // throws the same exceptions under the same circumstances
                // so we don't need to do any additional checking or work
                // here and let the Add implementation do all the heavy
                // lifting.
                //

                dict.Add(keySelector(item), elementSelector(item));
            }

            return dict;
        }

        /// <summary>
        /// Returns distinct elements from a sequence by using the default 
        /// equality comparer to compare values.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<T> Distinct()
        {
            return Distinct(null);
        }

        /// <summary>
        /// Returns distinct elements from a sequence by using a specified 
        /// <see cref="IEqualityComparer{T}"/> to compare values.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public LinqToObject<T> Distinct(IEqualityComparer<T> comparer)
        {
            return new LinqToObject<T>(DistinctYield(comparer));
        }

        /// <summary>
        /// Internal used by Distinct().
        /// </summary>
        /// <param name="comparer"></param>
        /// <returns></returns>
        [DebuggerStepThrough, DebuggerNonUserCode]
        private IEnumerable<T> DistinctYield(IEqualityComparer<T> comparer)
        {
            Dictionary<T, object> set = new Dictionary<T, object>(comparer);
            bool gotNull = false;

            foreach (T item in this)
            {
                // ReSharper disable CompareNonConstrainedGenericWithNull
                if (item == null)
                // ReSharper restore CompareNonConstrainedGenericWithNull
                {
                    if (gotNull)
                    {
                        continue;
                    }
                    gotNull = true;
                }
                else
                {
                    if (set.ContainsKey(item))
                    {
                        continue;
                    }
                    set.Add(item, null);
                }

                yield return item;
            }
        }
                
        /// <summary>
        /// Determines whether a sequence contains a specified element by 
        /// using the default equality comparer.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public bool Contains(T value)
        {
            return this.Contains(value, /* comparer */ null);
        }

        /// <summary>
        /// Determines whether a sequence contains a specified element by 
        /// using a specified <see cref="IEqualityComparer{T}" />.
        /// </summary>
        [DebuggerStepThrough, DebuggerNonUserCode]
        public bool Contains(T value, IEqualityComparer<T> comparer)
        {
            if (comparer == null)
            {
                ICollection<T> collection = this as ICollection<T>;
                if (collection != null)
                {
                    return collection.Contains(value);
                }
            }

            comparer = comparer ?? EqualityComparer<T>.Default;
            return this.Any(delegate(T item) { return comparer.Equals(item, value); });
        }

        #region Extension methods

        /// <summary>
        /// Gets result of this LinqToObject. WARNING: this will cause the whole query be executed,
        /// the result is not cached, use this wisely.
        /// </summary>
        public T[] Result
        {
            [DebuggerStepThrough]
            get { return this.ToArray(); }
        }

        // ====================================================================
        // Below methods do not exist in original LINQ set 
        // ====================================================================

        /// <summary>
        /// Attaches a Debug.Assert() to each of item.
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        [DebuggerNonUserCode]
        public LinqToObject<T> DebugAssert(Func<T, bool> predicate)
        {
            foreach (T item in this)
            {
                Debug.Assert(predicate(item));
            }

            return this;
        }

        /// <summary>
        /// Attaches a Debug.Assert() to the whole colleciton.
        /// </summary>
        /// <returns></returns>
        [DebuggerNonUserCode]
        public LinqToObject<T> DebugAssertCollection(Func<LinqToObject<T>, bool> predicate)
        {
            Debug.Assert(predicate(this));

            return this;
        }

        /// <summary>
        /// Attaches the specified action on each element of the LinqToObject(<see cref="T"/>) and continues the query chain.
        /// </summary>
        [DebuggerStepThrough]
        public LinqToObject<T> Each(Action<T> action)
        {
            return this.Each(delegate(T t, int index) { action(t); });
        }

        /// <summary>
        /// Attaches the specified action on each element of the LinqToObject(<see cref="T"/>) and continues the query chain.
        /// The index of element in the foreach loop with be passed to the method.
        /// </summary>
        [DebuggerStepThrough]
        public LinqToObject<T> Each(Action<T, int> action)
        {
            return new LinqToObject<T>(Yield<T, T>(this, delegate(T t, int index) { return t; }, null, action));
        }

        /// <summary>
        /// Executes the whole query and continues a new query chain.
        /// </summary>
        [DebuggerStepThrough]
        public LinqToObject<T> Execute()
        {
            return new LinqToObject<T>(this.ToArray());
        }

        #endregion
    }
}
// ReSharper restore CheckNamespace